package cn.yh.nft.turbo.chain.job;

import cn.hutool.core.lang.Chain;
import cn.yh.nft.turbo.api.chain.constant.ChainType;
import cn.yh.nft.turbo.api.chain.request.ChainProcessRequest;
import cn.yh.nft.turbo.api.chain.request.ChainQueryRequest;
import cn.yh.nft.turbo.api.chain.response.ChainProcessResponse;
import cn.yh.nft.turbo.api.chain.response.data.ChainResultData;
import cn.yh.nft.turbo.base.exception.BizException;
import cn.yh.nft.turbo.base.exception.RepoErrorCode;
import cn.yh.nft.turbo.base.exception.SystemException;
import cn.yh.nft.turbo.chain.domain.constant.ChainOperateStateEnum;
import cn.yh.nft.turbo.chain.domain.entity.ChainOperateInfo;
import cn.yh.nft.turbo.chain.domain.service.ChainOperateInfoService;
import cn.yh.nft.turbo.chain.domain.service.ChainService;
import cn.yh.nft.turbo.chain.domain.service.ChainServiceFactory;
import cn.yh.nft.turbo.chain.infrastructure.exception.ChainErrorCode;
import cn.yh.nft.turbo.chain.infrastructure.exception.ChainException;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @ClassName: ChainProcessJob
 * @Author: 草莓爱上啵啵
 *
 * 上链处理任务
 */

@Component
public class ChainProcessJob {

    @Autowired
    private ChainOperateInfoService chainOperateInfoService;

    @Autowired
    private ChainServiceFactory chainServiceFactory;

    private static final int PAGE_SIZE = 5;

    private static final Logger LOG = LoggerFactory.getLogger(ChainProcessJob.class);

    /**
     * 执行链式操作信息处理流程
     * 该方法负责分页查询并处理状态为处理中的链式操作信息
     *
     * @return ReturnT<String> 表示执行结果的状态
     */
    @XxlJob("unFinishOperateExecute")
    public ReturnT<String> execute() {
        // 查询链式操作信息中状态为处理中的最小ID
        Long minId = chainOperateInfoService.queryMinIdByState(ChainOperateStateEnum.PROCESSING.name());

        // 初始化链式操作信息列表
        List<ChainOperateInfo> chainOperateInfos = chainOperateInfoService.pageQueryOperateInfoByState(
                ChainOperateStateEnum.PROCESSING.name(), PAGE_SIZE, minId);

        // 当链式操作信息列表非空时，循环处理
        while (CollectionUtils.isNotEmpty(chainOperateInfos)){
            // 遍历列表，执行单个链式操作信息的处理
            chainOperateInfos.forEach(this::executeSingle);

            // 获取当前批次链式操作信息中的最大ID
            Long maxId = chainOperateInfos.stream().mapToLong(ChainOperateInfo::getId).max().orElse(Long.MAX_VALUE);

            // 根据最大ID查询下一批次的链式操作信息
            chainOperateInfos = chainOperateInfoService.pageQueryOperateInfoByState(ChainOperateStateEnum.PROCESSING.name(),
                    PAGE_SIZE, maxId + 1);
        }

        // 所有链式操作信息处理成功，返回成功状态
        return ReturnT.SUCCESS;
    }

    /**
     * 执行单个未完成的操作
     *
     * 本方法从链服务工厂获取相应的链服务，然后查询链操作结果
     * 如果查询成功且操作状态为成功，则发送消息并更新操作表状态
     * 如果查询失败或操作状态非成功，则抛出异常
     *
     * @param chainOperateInfo 链操作信息，包含链操作的详细信息
     */
    private void executeSingle(ChainOperateInfo chainOperateInfo) {
        //开始执行未完成操作的日志记录
        LOG.info("start to execute unfinish operate , id is {}", chainOperateInfo.getId());
        try{
            //根据链类型获取相应的链服务
            ChainService chainService = chainServiceFactory.get(ChainType.valueOf(chainOperateInfo.getChainType()));
            //创建查询请求
            ChainQueryRequest query = new ChainQueryRequest();
            query.setOperationId(chainOperateInfo.getOutBizId());
            //查询链操作结果
            ChainProcessResponse<ChainResultData> chainProcessResponse = chainService.queryChainResult(query);
            //查询失败处理
            if (!chainProcessResponse.getSuccess()){
                throw new ChainException(ChainErrorCode.CHAIN_QUERY_FAIL);
            }

            ChainResultData chainResultData = chainProcessResponse.getData();

            //异常情况判断
            if (null == chainResultData){
                throw new ChainException(ChainErrorCode.CHAIN_QUERY_FAIL);
            }

            //操作状态非成功处理
            if (!StringUtils.equals(chainResultData.getState(), ChainOperateStateEnum.SUCCEED.name())){
                throw new BizException(ChainErrorCode.CHAIN_PROCESS_STATE_ERROR);
            }

            //成功情况处理
            if (StringUtils.equals(chainResultData.getState(), ChainOperateStateEnum.SUCCEED.name())){
                //发送消息
                chainService.sendMsg(chainOperateInfo, chainResultData);
                //更新操作表状态
                //需要做核对，如果操作状态成功，相应业务表状态处理中，需要核对出来
                boolean updateResult = chainOperateInfoService.updateResult(chainOperateInfo.getId(),
                        ChainOperateStateEnum.SUCCEED, null);
                //更新失败处理
                if (!updateResult){
                    throw new SystemException(RepoErrorCode.UPDATE_FAILED);
                }
            }
        }catch (Exception e){
            //执行未完成操作发生错误的日志记录
            LOG.error("start to execute unfinish operate error, id is {}, error is {}", chainOperateInfo.getId(), e);
        }
    }
}
